#ifndef RAY_UTIL_H
#define RAY_UTIL_H

#include "mtxlib.h"
#include <time.h>

#define HIT		 1		
#define MISS	 0		
#define INPRIM	-1	
#define PLANE	10
#define SPHERE	11
#define LIGHT	20
#define NONLIGHT	21
#define MAXDISTANCE 1000000.0f
#define MAXDEPTH	6

class Pixel{

public:

	Pixel();
	~Pixel();
	void SetColor(float r, float g, float b);

	float red;
	float green;
	float blue;
};

class Screen{

public:
	 Screen(int width, int height, float windowL, float windowR, float windowT, float windowB);
	 ~Screen();
	 Pixel* GetScreenBuffer();


	 float windowLeft;
	 float windowRight;
	 float windowTop;
	 float windowBottom;
	 float windowHorizontalStep;
	 float windowVerticalStep;
	 Pixel *screenBuffer;
	 int screenWidth;
	 int screenHeight;	
};

class Ray{

public:

	Ray(){};
	~Ray(){};

	void SetOrigin(float x,float y, float z);
	void SetDirection(float x, float y, float z);

	vector3 origin;
	vector3 direction;
};

class Material{

public:

	Material(){};
	~Material(){};
	void SetReflaction(float refl);
	void SetOpticalFactor(float diff);
	void SetMaterialColor(float r, float g, float b);


	float diffuse;
	float specular;
	float reflaction;
	vector3 color;
};

class Object{

public:

	Object(){};
	virtual ~Object(){};
	virtual int IntersectTest(Ray& ray, float& dist)=0;
	virtual vector3 GetNormal(vector3& point)=0;
	void SetType(int geo);
	void SetLight(int opt);
	int GetGeometryType();
	int GetOpticalType();
	Material* GetMaterial();

private:

	int geometryType;
	int opticalType;
	Material material;
};

class Sphere:public Object{

public:
	
	~Sphere(){};
	int IntersectTest(Ray& ray, float& dist);
	vector3 GetNormal(vector3& point);
	Sphere(float r, vector3& c,int opt);
	float GetRadius();
	float GetSquareRadius();
	vector3& GetCenter();

private:
	vector3 center;
	float radius;
	float squareRadius;
	float reverseRadius;

};

class Plane:public Object{

public:
	
	~Plane(){};
	Plane(vector3& n, float dist, int opt);
	float GetDistance();
	vector3 GetNormal(vector3& point);
	int IntersectTest(Ray& ray, float& dist);

private:
	vector3 normal;
	float distance;
};

class Scene{

public:
	Scene(){numObjects=0;objects=0;};
	~Scene(){delete objects;};
	void InitScene();
	int GetObjectsNum();
	Object* GetObjectAt(int index);

private:
	int numObjects;
	Object** objects;
};

class Engine{

public:
	Engine(int width, int height, float windowL, float windowR, float windowT, float windowB);
	~Engine();
	bool Render();
	Object* RayTrace(Ray& ray, vector3& color, int depth, float dist);
	Scene* GetScene();
	Screen* GetScreen();
	


private:
	int currentLine;
	float currentX;
	float currentY;
	Scene* scene;
	Screen* screen;
};

inline vector3 VectorProduct(vector3& va, vector3& vb);

#endif
